/* thread.c : dgnsc thread
 * Copyright (C) 2009-2010 drangon <drangon.zhou@gmail.com>
 * 2009-05
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <dgnsc/thread.h>

#ifdef _WIN32
#include <windows.h>
#include <process.h>
#else
#include <stdlib.h>
#include <pthread.h>
#endif

struct dgn_thread_st
{
#ifdef _WIN32
	HANDLE tid;
#else
	pthread_t tid;
#endif
	dgn_thread_func_t func;
	void * arg;
	void * tag;
};

#ifdef _WIN32
static unsigned __stdcall s_wrap_thread_func( void * thd )
{
	struct dgn_thread_st * th = (struct dgn_thread_st *)thd;
	(* th->func)( (dgn_thread_t)th, th->arg );
	_endthreadex( 0 );
	return 0;
}

#else
static void * s_wrap_thread_func( void * thd )
{
	struct dgn_thread_st * th = (struct dgn_thread_st *)thd;
	(* th->func)( (dgn_thread_t)th, th->arg );
	return (void *)0;
}
#endif

dgn_thread_t dgn_thread_create( dgn_thread_func_t thfunc, void * arg, void * tag )
{
	struct dgn_thread_st * th = (struct dgn_thread_st *)malloc( sizeof(struct dgn_thread_st) );
	th->func = thfunc;
	th->arg = arg;
	th->tag = tag;

#ifdef _WIN32
	th->tid = (HANDLE)_beginthreadex( NULL, 0, &s_wrap_thread_func, (void *)th, 0, NULL );
	if( th->tid == 0 ) {
		free( th ), th = NULL;
	}

#else
	int tmp = pthread_create( &th->tid, NULL, &s_wrap_thread_func, (void *)th );
	if( tmp < 0 ) {
		free( th ), th = NULL;
	}
#endif
	return (dgn_thread_t)th;
}

void * dgn_thread_get_tag( dgn_thread_t thd )
{
	struct dgn_thread_st * th = (struct dgn_thread_st *)thd;
	return th->tag;
}

void dgn_thread_set_tag( dgn_thread_t thd, void * tag )
{
	struct dgn_thread_st * th = (struct dgn_thread_st *)thd;
	th->tag = tag;
	return;
}

int dgn_thread_wait_destroy( dgn_thread_t thd )
{
	struct dgn_thread_st * th = (struct dgn_thread_st *)thd;
#ifdef _WIN32
	WaitForSingleObject( th->tid, INFINITE );
	CloseHandle( th->tid );
#else
	void * tmp = NULL;
	pthread_join( th->tid, &tmp );
#endif
	free( th );
	return 0;
}

